/* 
 * Copyright 2009 Shared Object (www.sharedobject.ch)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package activity;

import java.util.Set;

import edos.prm.activity.Activity;
import edos.prm.activity.Operation.PrmOperation;
import edos.prm.artifact.ArtifactManager;
import edos.prm.artifact.ArtifactSet;
import edos.prm.artifact.AttributePair;
import edos.prm.artifact.UnregisteredArtifactType;
import edos.prm.artifact.ArtifactManager.PrmArtifactManager;
import edos.prm.engine.PRM;
import edos.prm.engine.PrmSecurityManager;
import edos.prm.event.Event;
import edos.prm.event.EventManager;
import edos.prm.event.EventManager.PrmEventManager;
import edos.prm.util.Time;
import edos.prm.util.VersionNumber;

/**
 * The {@code ProductionActivity} is the activity that handles the management
 * of balloons.
 */
public final class ProductionActivity implements Activity {

	private ArtifactSet<Balloon> balloonSet;
	private ArtifactManager artifactManager;
	private EventManager eventManager;
	private Time creationDate;

	public ProductionActivity() {
		this.balloonSet = new ArtifactSet<Balloon>();
		this.artifactManager = PrmArtifactManager.getInstance();
		this.artifactManager.registerArtifactType(Balloon.class);
		this.eventManager = PrmEventManager.getInstance();
		this.artifactManager.registerArtifactType(StockLevel.class);
		this.creationDate = new Time();
	}

	/**
	 * Creates a balloon of the specified size and license.
	 * <p>
	 * This operation invokes {@code ArtifactManager} to have the newly created
	 * balloon registered with the PRM engine.
	 * 
	 * @param license the license associated with the balloon
	 * @param size the size of the balloon, between 1 an 10
	 * @return a new balloon
	 * @throws UnregisteredArtifactType if balloon type has not been
	 * registered with the artifact manager.
	 */
	public Balloon createBalloon(License license, Integer size)
	throws UnregisteredArtifactType {
		PrmSecurityManager.roleCheck("createBalloon", getClass(), new Class[] {License.class, Integer.class});
		//Balloon balloon = (Balloon) this.artifactManager.
		//newArtifact(Balloon.class.getName(), new Object[] {license, size});
		Balloon balloon = new Balloon(license, size);
		this.artifactManager.registerArtifact(balloon);
		balloonSet.add(balloon);
		return balloon;
	}

	/**
	 * This operation takes a specified number of balloons from the stock. All
	 * balloons must be of the given size.
	 * 
	 * @param size the size of the requested balloons
	 * @param number the number of balloons to consume.
	 * @return a set of balloons of the requestedd size
	 */
	public Set<Balloon> consumeBalloons(Integer size, Integer number) {
		PrmSecurityManager.roleCheck("consumeBalloons", getClass(), new Class[] {Integer.class, Integer.class});
		ArtifactSet<Balloon> resultSet = new ArtifactSet<Balloon>();
		Set<Balloon> set = this.balloonSet.getContents();
		for ( Balloon b : set ) {
			if ( b.getSize() == size ) {
				resultSet.add(b);
				this.balloonSet.remove(b);
			}
			if ( resultSet.size() == number )
				break;
		}
		//balloonSet.remove(balloon);
		return resultSet.getContents();
	}

	/**
	 * Return the number of balloons currently in stock.
	 * 
	 * @return the number of balloon as an int
	 */
	public int numberOfBalloons() {
		PrmSecurityManager.roleCheck("numberOfBalloons", getClass());
		return this.balloonSet.size();
	}

	public void signalStockLevel(Integer level, Integer balloonSize) {
		PrmSecurityManager.roleCheck("signalStockLevel", getClass(), new Class[] {Integer.class, Integer.class});
		try {
			Event event = eventManager.newEvent(StockLevel.class,
					level, balloonSize);
			this.eventManager.raiseEvent(event);
		} catch (UnregisteredArtifactType e) {
			e.printStackTrace();
		}
	}

	public int detectStockLevel(Integer level) {
		PrmSecurityManager.roleCheck("detectStockLevel", getClass(), Integer.class);
		while ( true ) {
			StockLevel sl = (StockLevel)eventManager.
			observe(new AttributePair<Class<?>>("getClass", StockLevel.class));
			if ( sl.getStockLevel() <= level )
				return sl.getBalloonSize();
		}
	}

	public Time getCreationDate() {
		return this.creationDate;
	}

	public String getDescription() {
		return "Production Activity for Balloons";
	}

	public VersionNumber getVersion() {
		return PRM.getPRMVersion();
	}
}
